package io.perfeccionista.framework.invocation.runner;

import io.perfeccionista.framework.Environment;
import io.perfeccionista.framework.exceptions.PreconditionViolation;
import io.perfeccionista.framework.exceptions.attachments.WebAllureAttachmentProcessor;
import io.perfeccionista.framework.exceptions.base.PerfeccionistaAssertionError;
import io.perfeccionista.framework.exceptions.base.PerfeccionistaRuntimeException;
import io.perfeccionista.framework.pagefactory.dispatcher.WebBrowserService;
import io.perfeccionista.framework.screenshots.Screenshot;
import io.qameta.allure.Allure;
import io.qameta.allure.model.Status;
import org.jetbrains.annotations.NotNull;

import java.io.ByteArrayInputStream;
import java.util.Optional;
import java.util.function.Consumer;

import static io.qameta.allure.Allure.getLifecycle;
import static io.qameta.allure.util.ResultsUtils.getStatus;
import static io.qameta.allure.util.ResultsUtils.getStatusDetails;

public class ExceptionInnerInvocationInfoCheckVisitor implements Consumer<InvocationInfo> {
    private final WebAllureAttachmentProcessor attachmentProcessor = new WebAllureAttachmentProcessor(Environment.getCurrent());

    @Override
    public void accept(InvocationInfo invocationInfo) {
        boolean primaryExceptionProcessed = Optional.ofNullable(WebAllureMultipleAttemptInvocationRunner.primaryExceptionProcessed.get())
                .orElse(false);
        Throwable throwable = invocationInfo.getCurrent()
                .orElseThrow(() -> PreconditionViolation.exception("On stage 'exception' current result can't be null"))
                .getThrowable()
                .orElseThrow(() -> PreconditionViolation.exception("Exception status is set together with the exception"));
        if (!primaryExceptionProcessed) {
            Allure.addAttachment("Execution statistics", invocationInfo.getStatistics());
            if (throwable instanceof PerfeccionistaRuntimeException) {
                PerfeccionistaRuntimeException exception = ((PerfeccionistaRuntimeException) throwable);
                exception.prepareAttachmentDescription();
                exception.getAttachment().ifPresent(attachmentProcessor::processAttachment);
            }
            if (throwable instanceof PerfeccionistaAssertionError) {
                PerfeccionistaAssertionError assertionError = ((PerfeccionistaAssertionError) throwable);
                assertionError.prepareAttachmentDescription();
                assertionError.getAttachment().ifPresent(attachmentProcessor::processAttachment);
            }
            takeScreenshot(Environment.getCurrent()).ifPresent(screenshot ->
                    Allure.addAttachment("Web Browser Screenshot",
                            "image/png",
                            new ByteArrayInputStream(screenshot.getRaw()),
                            "png"));
            attachmentProcessor.processAttachment(invocationInfo.getAttachment());
        }
        getLifecycle().updateStep(invocationInfo.getUuid(), step -> step
                .setStatus(getStatus(throwable).orElse(Status.BROKEN))
                .setStatusDetails(getStatusDetails(throwable).orElse(null)));
        attachmentProcessor.processAttachment(invocationInfo.getAttachment());
        getLifecycle().stopStep(invocationInfo.getUuid());
    }

    protected Optional<Screenshot> takeScreenshot(@NotNull Environment environment) {
        WebBrowserService webBrowserService = environment.getService(WebBrowserService.class);
        if (webBrowserService.isActiveDispatcherRunning()) {
            return Optional.of(webBrowserService.getActiveDispatcher()
                    .window()
                    .getPageScreenshot());
        }
        return Optional.empty();
    }

}


